package eiisan.config.aop.util;

import eiisan.config.aop.validation.annotation.Check;
import eiisan.constant.errors.exception.CodeCheckException;
import eiisan.service.task.dto.AvailableTaskDTO;
import eiisan.util.common.EmptyUtil;
import eiisan.util.model.response.PageData;
import eiisan.util.model.response.Result;
import eiisan.util.reflect.ReflectUtil;
import lombok.experimental.UtilityClass;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.ListenableFuture;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * AOP工具类
 */
@UtilityClass
public class AOPUtil {

    /**
     * 判断方法返回类型是否为AsyncResult-即ListenableFuture(类型参数T为Result)<br>
     * 如果是AsyncResult,返回true.如果是Result,返回false.<br>
     * 如果既不是AsyncResult,也不是Result,则抛出异常.<br>
     *
     * @see org.springframework.util.concurrent.ListenableFuture
     * @see eiisan.util.model.response.Result
     */
    public static boolean isAsyncResultAsReturn(Method method) throws CodeCheckException {
        Assert.notNull(method, "method must not be null");
        Type type = method.getAnnotatedReturnType().getType();
        if (isAsyncResult(type)) {
            return true;
        }
        if (isResult(type)) {
            return false;
        }
        throw new CodeCheckException("含有", "@", Check.class.getCanonicalName(), "注解的方法", ReflectUtil.getFullMethodName(
                method), "的返回值类型必须为", ListenableFuture.class.getCanonicalName(), "或者", Result.class.getCanonicalName());
    }

    /**
     * 判断方法返回类型是否为Result<br>
     * 如果是Result,返回true.如果是AsyncResult,返回false.<br>
     * 如果既不是AsyncResult-即ListenableFuture(类型参数T为Result),也不是Result,则抛出异常.<br>
     *
     * @see org.springframework.util.concurrent.ListenableFuture
     * @see eiisan.util.model.response.Result
     */
    public static boolean isResultAsReturn(Method method) throws CodeCheckException {
        Assert.notNull(method, "method must not be null");
        Type type = method.getAnnotatedReturnType().getType();
        if (isResult(type)) {
            return true;
        }
        if (isAsyncResult(type)) {
            return false;
        }
        throw new CodeCheckException("含有", "@", Check.class.getCanonicalName(), "注解的方法", ReflectUtil.getFullMethodName(
                method), "的返回值类型必须为", ListenableFuture.class.getCanonicalName(), "或者", Result.class.getCanonicalName());
    }

    private static boolean isResult(Type type) {
        if (type instanceof Class) {
            return Result.class.isAssignableFrom((Class<?>) type);
        }
        if (type instanceof ParameterizedType) {
            Type rawType = ((ParameterizedType) type).getRawType();
            return Result.class.isAssignableFrom((Class<?>) rawType);
        }
        return false;
    }

    private static boolean isAsyncResult(Type type) {
        if (!(type instanceof ParameterizedType)) {
            return false;
        }
        Type rawType = ((ParameterizedType) type).getRawType();
        if (!(rawType instanceof Class) || !ListenableFuture.class.isAssignableFrom((Class<?>) rawType)) {
            return false;
        }
        Type[] types = ((ParameterizedType) type).getActualTypeArguments();
        if (EmptyUtil.yes(types)) {
            return false;
        }
        Type typeArgument = types[0];
        return isResult(typeArgument);
    }

}
